package com.example.demo.service;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.demo.domain.LoginDto;
import com.example.demo.domain.MyUserDetails;
import com.example.demo.domain.User;
import com.example.demo.exception.ResultException;
import com.example.demo.mapper.UserMapper;
import com.example.demo.utils.JwtUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.lang.module.ResolutionException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author wsj
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserService implements UserDetailsService, LogoutSuccessHandler {
    private final UserMapper userMapper;
    private final AuthenticationManager authenticationManager;
    private final RedisTemplate<String, String> redisTemplate;
    private final JwtUtil jwtUtil;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username);
        User user = userMapper.selectOne(queryWrapper);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在： " + username);
        }
        MyUserDetails myUserDetails = new MyUserDetails(user);
        return myUserDetails;
    }

    public String login(LoginDto loginDto) {
        //1.从loginDto中获取用户名和密码并且创建一个UsernamePasswordAuthenticationToken对象
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
        //2.调用AuthenticationManager的authenticate方法进行认证
        Authentication authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        if (authentication == null) {
            throw new ResultException(401, "用户名或密码错误");
        }
        //3.获取认证成功后的用户信息
        Object principal = authentication.getPrincipal();
        MyUserDetails myUserDetails = (MyUserDetails) principal;
        log.info("用户登录成功，用户名：{}, 密码：{}", myUserDetails.getUsername(), myUserDetails.getPassword());
        //4.生成token，将用户信息保存到redis中
        String token = jwtUtil.generateToken(myUserDetails.getId());
        redisTemplate.opsForValue().set(String.valueOf(myUserDetails.getId()),JSONUtil.toJsonStr(myUserDetails), 1, TimeUnit.DAYS);
        return token;
    }

    public void logout() {
    }

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        String token = request.getHeader("token");
        redisTemplate.delete(token);
        Map<String, Object> map = new HashMap<>();
        map.put("code", 200);
        map.put("msg", "退出成功");
        // 响应数据
        response.getWriter().write(JSONUtil.toJsonStr(map));
        // 设置响应头(告诉浏览器返回的数据类型为json)
        response.setContentType("application/json;charset=UTF-8");
    }
}
